/*********************************************************************************
 * Software License Agreement (BSD License)
 * Copyright (c) 2012, Carlos D. Correa (info@ngraph.org)
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * 
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of netzen nor the
 *    names of its contributors may be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *********************************************************************************/
#include "controller.h"
#include "glheaders.h"
#include "view.h"
#include "graph.h"
#include <assert.h>
#include <string.h>
#include <fstream>
#include <algorithm>

using namespace std;

Controller::Controller(): Object("Controller", "singleton") {
    viewManager = 0;
    renderUI = 0;
    dataControl = new DataControl("controller");
    dataControl->setController(this);
		dataControl->loadMetadata("netzen.metadata.default");
		dataControl->loadMetadata("user.metadata.default");
		dataControl->loadColors("netzen.colors");
		dataControl->loadColors("user.colors");
    // Some initial virtual properties
		addVirtualProperty(Controller::addVirtualPrefix("node.color"), "node");
    addVirtualProperty(Controller::addVirtualPrefix("node.colormap"), "colormap");
    addVirtualProperty(Controller::addVirtualPrefix("node.size"), "node");
    addVirtualProperty(Controller::addVirtualPrefix("edge.color"), "edge");
    addVirtualProperty(Controller::addVirtualPrefix("edge.colormap"), "colormap");
    addVirtualProperty(Controller::addVirtualPrefix("selection.colormap"), "colormap");
    setVirtualProperty(Controller::addVirtualPrefix("selection.colormap"), "qualitative_d"); 
		setVirtualProperty(Controller::addVirtualPrefix("selection.colormap"), "qualitative_d"); //this causing problem for selection widget
		setVirtualProperty(Controller::addVirtualPrefix("selection.colormap"), "qualitative_d"); //this causing problem for selection widget
    //setVirtualProperty(addVirtualPrefix("selection.colormap"), "Default");
}
Controller::~Controller() {
    // Delete views
    for(map<string,View*>::const_iterator it = views.begin(); it !=views.end(); ++it) {
        if(it->second) {
            delete(it->second);
        }
    }
    for(map<string,AnalysisTool*>::const_iterator it = tools.begin(); it !=tools.end(); ++it) {
        delete(it->second);
    }
    for(map<string,Layout*>::const_iterator it = layouts.begin(); it !=layouts.end(); ++it) {
        delete(it->second);
    }
    for(map<string,Graph*>::const_iterator it = graphs.begin(); it !=graphs.end(); ++it) {
        delete(it->second);
    }

}

void Controller::importTable(Graph *g, const char *file) {
    sources.push_back(string(file));
    dataControl->importTable(g, file);
    notifyDataAdded(file, "importTable");
}

void Controller::importEdgeTable(Graph *g, const char *file, bool undirected) {
    sources.push_back(string(file));
    dataControl->importEdgeTable(g, file, undirected);
    notifyDataAdded(file, "importEdgeTable");
}

void Controller::importFloat(Graph *g, const char *file, const char *property) {
    dataControl->importFloat(g, file, property);
}

void Controller::exportFloat(Graph *g, const char *file, const char *property) {
    dataControl->exportFloat(g, file, property);
}

void Controller::importImplicitEdgeFloat(Graph *g, const char *file, const char *property) {
    dataControl->importImplicitEdgeFloat(g, file, property);
}

void Controller::exportImplicitEdgeFloat(Graph *g, const char *file, const char *property) {
    dataControl->exportImplicitEdgeFloat(g, file, property);
}

void Controller::importEdgeFloat(Graph *g, const char *file, const char *property) {
    dataControl->importEdgeFloat(g, file, property);
}

void Controller::exportEdgeFloat(Graph *g, const char *file, const char *property) {
    dataControl->exportEdgeFloat(g, file, property);
}

void Controller::execute(string cmd, const char* file, const char* property) {
    Graph *graph = getGraph("graph");
    assert(graph);

    if(cmd=="importTable") {
        importTable(graph, file);
    }
    if(cmd=="importEdgeTable") {
        importEdgeTable(graph, file, true);
    }
    if(cmd=="importDirectedEdgeTable") {
        importEdgeTable(graph, file, false);
    }
    if(cmd=="loadWorkspace") {
        loadWorkspace(file);
    }
    if(cmd=="importFloat") {
        importFloat(graph, file, property);
    }
    if(cmd=="importImplicitEdgeFloat") {
        importImplicitEdgeFloat(graph, file, property);
    }
    if(cmd=="importEdgeFloat") {
        importEdgeFloat(graph, file, property);
    }

}

void Controller::readScript(const char *name) {
    FILE *fp = fopen(name,"r"); //
    if(!fp) {
        print("Cannot open script %s\n", name);
        return;
    }
    char line[512];
    fgets(line, 512, fp);
    while(!feof(fp)) {
        char cmd[250];
        char file[200];
        char prop[200];
        print("Read line %s\n", line);
        if(strlen(line)>0) {
            int params = sscanf(line, "%s %s %s", cmd, file, prop);
            if(params>=2) {
                execute(cmd, file, prop);
            }
        }
        fgets(line, 512, fp);
    }

    fclose(fp);
    print("Read script %s\n", name);
}

void Controller::updateRender() {
    if(renderUI) {
        renderUI->redraw();
    }
}
void Controller::setRenderUI(RenderUI *renderUI) {
    this->renderUI = renderUI;
}
RenderUI *Controller::getRenderUI() {
    return renderUI;
}

void Controller::registerProperty(string type, string prop) {
    mapProperties[type].insert(prop);
    notifyPropertyChanged(type);
}

vector<string> Controller::getRegisteredLists() {
    vector<string> lists;
    for(map<string,stringArray>::const_iterator it = mapProperties.begin(); it !=mapProperties.end(); ++it) {
        lists.push_back((it->first));
    }
    return lists;
}

vector<string> Controller::getRegisteredProperties(string type) {
    vector<string> props;
    for(set<string>::const_iterator it = mapProperties[type].begin();it !=mapProperties[type].end(); ++it) {
        props.push_back(*it);
    }
    return props;
}

void Controller::addPropertyListener(PropertyListener *l) {
    assert(l);
    listeners.push_back(l);
}
void Controller::notifyPropertyChanged(string name) {
    for(unsigned int i=0;i<listeners.size();i++) {
        listeners[i]->propertyChanged(name);
    }
}

void Controller::addGraph(string name, Graph *g) {
    graphs[name] = g;
}

Graph * Controller::getGraph(string name) {
    return graphs[name];
}

void Controller::addTool(AnalysisTool *t) {
    tools[t->getName()] = t;
}

AnalysisTool * Controller::getTool(string name) {
    return tools[name];
}

void Controller::executeTool(string name) {
    tools[name]->compute();
}

vector<ToolInfo> Controller::getTools() {
    vector<ToolInfo> vec;
    for(map<string,AnalysisTool*>::const_iterator it = tools.begin(); it !=tools.end(); ++it) {
	if(!it->second) continue;
        ToolInfo info;
        info.name = it->first;
        info.type = it->second->getType();
        vec.push_back(info);
    }
    return vec;
}

void Controller::setToolProperty(AnalysisTool *tool, string property, string value) {
    assert(tool);
    tool->setProperty(property, value);
}


/*************** VIEWS ******************/
void Controller::addView(View *view) {
    assert(view);
    views[view->getName()] = view;
    notifyViewAdded(view);
}

View *Controller::getView(string name) {
    return views[name];
}

vector<ViewInfo> Controller::getViews() {
    vector<ViewInfo> vec;
    for(map<string,View*>::const_iterator it = views.begin(); it !=views.end(); ++it) {
        ViewInfo info;
        if(!(it->second)) {
            print("Strange. I can't find a valid object for %s\n", it->first.c_str());
            continue;
        }
        //print("Info %s\n", it->first.c_str());
        info.name = it->first;
        //print("Type %s\n", it->second->getType().c_str());
        info.type = it->second->getType();
        vec.push_back(info);
    }
    return vec;
}

void Controller::setViewProperty(View *view, string property, string value) {
    assert(view);
    view->setProperty(property, value);
    updateRender();
}


View *Controller::createView(string type, string /*name*/) {
    if(viewCreators.find(type)==viewCreators.end()) return 0;
    ViewCreatorFn * fn = viewCreators[type];
    if(!fn) return 0;
    if(numViewInstances.find(type)==numViewInstances.end()) {
        numViewInstances[type] = 0;
    }
    int numInstances = numViewInstances[type];
    char strName[200];
    sprintf(strName, "%s_%d", type.c_str(), numInstances+1);
    View * view = fn(string(strName));
    view->controller = this;
    view->setGraph(getGraph("graph"));
    view->setCreator(type);
		view->setLocation(-0.8, 0.8);
		view->setSize(1.6, 1.6);
    numViewInstances[type] = numInstances+1;
    addView(view);
    return view;
}

void Controller::addViewCreator(string type, ViewCreatorFn * fn) {
    viewCreators[type] = fn;
}

vector<string> Controller::getViewCreators() {
    vector<string> vec;
    for(map<string,ViewCreatorFn *>::const_iterator it = viewCreators.begin(); it !=viewCreators.end(); ++it) {
        string name = it->first;
        vec.push_back(name);
    }
    return vec;
}

void Controller::addViewListener(ViewListener *l) {
    assert(l);
    viewListeners.push_back(l);
}
void Controller::notifyViewAdded(View *view) {
    for(unsigned int i=0;i<viewListeners.size();i++) {
        viewListeners[i]->viewAdded(view);
    }
}

/*************** LAYOUTS ******************/
void Controller::addLayout(Layout *layout) {
    assert(layout);
    layouts[layout->getName()] = layout;
    registerProperty("layout", layout->getName());
    notifyLayoutAdded(layout);
}

Layout *Controller::getLayout(string name) {
    return layouts[name];
}

void Controller::executeLayout(string name) {
    if(layouts[name]) layouts[name]->compute();
}

vector<LayoutInfo> Controller::getLayouts() {
    vector<LayoutInfo> vec;
    for(map<string,Layout*>::const_iterator it = layouts.begin(); it !=layouts.end(); ++it) {
        LayoutInfo info;
        if(!(it->second)) {
            print("Strange. I can't find a valid object for %s\n", it->first.c_str());
            continue;
        }
        //print("Info %s\n", it->first.c_str());
        info.name = it->first;
        //print("Type %s\n", it->second->getType().c_str());
        info.type = it->second->getType();
        vec.push_back(info);
    }
    return vec;
}

Layout *Controller::createLayout(string type, string /*name*/) {
    if(layoutCreators.find(type)==layoutCreators.end()) return 0;
    LayoutCreatorFn * fn = layoutCreators[type];
    if(!fn) return 0;
    if(numLayoutInstances.find(type)==numLayoutInstances.end()) {
        numLayoutInstances[type] = 0;
    }
    int numInstances = numLayoutInstances[type];
    char strName[200];
    sprintf(strName, "%s_%d", type.c_str(), numInstances+1);
    Layout * layout = fn(string(strName));
    layout->setGraph(getGraph("graph"));
    layout->setCreator(type);
    layout->controller = this;
    numLayoutInstances[type] = numInstances+1;
    addLayout(layout);
    return layout;
}

void Controller::addLayoutCreator(string type, LayoutCreatorFn * fn) {
    layoutCreators[type] = fn;
}

vector<string> Controller::getLayoutCreators() {
    vector<string> vec;
    for(map<string,LayoutCreatorFn *>::const_iterator it = layoutCreators.begin(); it !=layoutCreators.end(); ++it) {
        string name = it->first;
        vec.push_back(name);
    }
    return vec;
}

void Controller::addLayoutListener(LayoutListener *l) {
    assert(l);
    layoutListeners.push_back(l);
}
void Controller::notifyLayoutAdded(Layout *layout) {
    for(unsigned int i=0;i<layoutListeners.size();i++) {
        layoutListeners[i]->layoutAdded(layout);
    }
}

void Controller::setLayoutProperty(Layout *layout, string property, string value) {
    assert(layout);
    layout->setProperty(property, value);
}

void Controller::layoutUpdated() {
    for(map<string,View*>::const_iterator it = views.begin(); it !=views.end(); ++it) {
        if(it->second) {
            it->second->layoutUpdated();
        }
    }
}


/*************** WORKSPACES ******************/
bool Controller::loadWorkspace(const char *name) {
    ifstream inp(name);

    if(!inp.is_open()) {
        string strName = "";
        bool retry = this->retryOpenFile(name,strName);
        if(!retry){
            return false;
            error("Cannot open workspace %s\n", name);
        }
        inp.open(strName.c_str(), ifstream::in);
    }

    string line;
    getline(inp, line);
    if(line!="BEGIN MAPPING") {
        return false;
    }

    getline(inp, line);
    while(line!="END" && !inp.eof()) {
        //char prop[255];
        //char value[255];
	//char type[255];
        char *prop = strtok((char*) line.c_str(), "\t");
        char *value = strtok(NULL, "\t");
        char *type = strtok(NULL, "\t\n");
        if(prop && value && type) {
            addVirtualProperty(string(prop), string(type));
            setVirtualProperty(string(prop), string(value));

            // 0620 : notify so Mapping tab knows.
            this->notifyPropertyChanged(string(prop));
	}
        else{ // null value; type (eg. edge, node) is saved in value
            type = value;
            addVirtualProperty(string(prop), string(type));
            //setVirtualProperty(string(prop), "Default");
        }



        getline(inp, line);
    }

    View *view = 0;
    Layout *layout = 0;
    getline(inp, line);
    vector<string> custom;
    bool readingCustom = false;
    float x,y,w,h;
    x = y = 0; w = h = 1.0;
    while(!inp.eof()) {
       // print("Line = [%s]\n", line.c_str());
        string header = "BEGIN VIEW ";
        string headerLayout = "BEGIN LAYOUT ";
        if(line=="END_CUSTOM") {
            readingCustom = false;
            if(view) view->load(custom);
        } else if(readingCustom) {
            custom.push_back(line);
        } else if(line.substr(0, header.length())==header) {
            string type = line.substr(header.length());
            view = createView(type,type);
						print("Create view of type [%s]\n", type.c_str());
        } else if(line.substr(0, headerLayout.length())==headerLayout) {
            string type = line.substr(headerLayout.length());
            layout = createLayout(type,type);
        } else if(line=="END") {
            if(view) {
		view->setLocation(x,y);
		view->setSize(w,h);
            }
            view = 0;
            layout = 0;
        } else if(line=="CUSTOM") {
            custom.clear();
            readingCustom = true;
        } else if(view && !readingCustom) {
            const char *prop = strtok((char*) line.c_str(), "\t");
            const char *value = strtok(NULL, "\t");
            if(string(prop)=="X") {
		x = atof(value);
            } else if(string(prop)=="Y") {
		y = atof(value);
            } else if(string(prop)=="W") {
		w = atof(value);
            } else if(string(prop)=="H") {
		h = atof(value);
            } else {
							if(!value) value = "";
							print("Found pair %s %s of type %d - %s\n", prop, value, view->getPropertyType(prop), view->getPropertyListModel(prop).c_str());
							view->setProperty(prop, value);
            }
        } else if(layout) {
            const char *prop = strtok((char*) line.c_str(), "\t");
            const char *value = strtok(NULL, "\t");
            layout->setProperty(prop, value);
            layout->update(prop);
	}
        line = "";
        getline(inp, line);
    }


    inp.close();
    updateRender();
    return true;
}

vector<string> Controller::getVirtualProperties() {
    vector<string> values;
    for(map<string,string>::const_iterator it = virtualProperties.begin(); it!=virtualProperties.end(); it++) {
        string s = (it->first);
        values.push_back(s);
    }
    return values;
}

bool Controller::saveWorkspace(const char *name) {
    FILE *fp = fopen(name, "w");
    fprintf(fp, "BEGIN MAPPING\n");
    if(!fp) return false;

    vector<string> properties = getVirtualProperties();
    for(unsigned int i=0;i<properties.size();i++) {
        string value = getVirtualProperty(properties[i]);
		string type = getVirtualPropertyType(properties[i]);
        fprintf(fp, "%s\t%s\t%s\n", properties[i].c_str(), value.c_str(), type.c_str());
    }
    fprintf(fp, "END\n");

    // Save Views
    vector<ViewInfo> info =  getViews();
    for(unsigned int i = 0; i < info.size(); i++) {
        string name = info[i].name;
        string type = info[i].type;
        View *view = getView(name);
        assert(view);
        string creator = view->getCreator();

        fprintf(fp, "BEGIN VIEW %s\n", creator.c_str());
        float x, y, w, h;
        view->getLocation(x,y);
        view->getSize(w,h);
        fprintf(fp, "X\t%f\n",x);
        fprintf(fp, "Y\t%f\n",y);
        fprintf(fp, "W\t%f\n",w);
        fprintf(fp, "H\t%f\n",h);
        vector<string> props = view->getProperties();
        for(unsigned int i=0;i<props.size();i++) {
            string prop = props[i];
						string value = view->getAsString(prop);
            fprintf(fp, "%s\t%s\n",prop.c_str(), value.c_str());
        }
        fprintf(fp, "CUSTOM\n");
        view->save(fp);
        fprintf(fp, "END_CUSTOM\n");
        fprintf(fp, "END\n");
    }

    // Save Layouts
    vector<LayoutInfo> infoL =  getLayouts();
    for(unsigned int i = 0; i < infoL.size(); i++) {
        string name = infoL[i].name;
        string type = infoL[i].type;
        Layout *layout = getLayout(name);
        assert(layout);
        string creator = layout->getCreator();

        fprintf(fp, "BEGIN LAYOUT %s\n", creator.c_str());
        vector<string> props = layout->getProperties();
        for(unsigned int i=0;i<props.size();i++) {
            string prop = props[i];
					string value = layout->getAsString(prop);
            fprintf(fp, "%s\t%s\n",prop.c_str(), value.c_str());
        }
        //fprintf(fp, "CUSTOM\n");
        //layout->save(fp);
        //fprintf(fp, "END_CUSTOM\n");
        fprintf(fp, "END\n");
        layout->save();
    }

    fclose(fp);
    return true;
}

// Property Management
void Controller::addDataProperty(string element, string name, int type) {
		registerProperty(element, name);
    propertyTypes[name] = type;
}
int Controller::getPropertyType(string name) {
    return propertyTypes[name];
}

// Virtual Properties
bool Controller::isVirtualProperty(string property) {
    int found = property.find("$");
    if(found>0) {
        // This is not a data property, but a virtual property
        string prefix = property.substr(0, found);
        string suffix = property.substr(found+1);
        if(prefix=="_Virtual") {
            return true;
        }
    }
    return false;
}
string Controller::extractPropertyName(string property) {
    string newProp = property;
    int found = property.find("$");
    if(found>0) {
        // This is not a data property, but a virtual property
        string prefix = property.substr(0, found);
        string suffix = property.substr(found+1);
        if(prefix=="_Virtual") {
            newProp = property;
        }
    }
    printf("Extract propertyName[%s]->[%s]\n", property.c_str(), newProp.c_str());
    return newProp;
}

string Controller::addVirtualPrefix(string property) {
    return "_Virtual$"+property;
}

string Controller::addVirtualProperty(string virtualName, string type) {
    string newName = virtualName;
    if(virtualProperties.find(newName)!=virtualProperties.end()) {
        return newName;
    }

    virtualProperties[newName] = "";
    virtualPropertyTypes[newName] = type;
    registerProperty(type, newName);
    return newName;
}
void Controller::setVirtualProperty(string virtualName, string dataName) {
    virtualProperties[virtualName] = dataName;
    colorUpdated();
}
string Controller::getVirtualProperty(string virtualName) {
    return virtualProperties[virtualName];
}
string Controller::getVirtualPropertyType(string virtualName) {
    return virtualPropertyTypes[virtualName];
}

// Color
void Controller::getColor(string cmap, float f, float *rgb) {
    rgb[0] = rgb[1] = rgb[2] = 0.0;
    if(!colormaps[cmap]) return;
    assert(colormaps[cmap]);
    colormaps[cmap]->getColor(f, rgb);
}

void Controller::getColor(string cmap, int i, float *rgb) {
    if(!colormaps[cmap]) return;
    assert(colormaps[cmap]);
    colormaps[cmap]->getColor(i, rgb);
}

void Controller::addColormap(string name, ColorMap *c) {
    c->setController(this);
    colormaps[name] = c;
}

ColorMap * Controller::getColormap(string cmap) {
    return colormaps[cmap];
}

void Controller::colorUpdated() {
    //print("Color updated\n");
    for(map<string,View*>::const_iterator it = views.begin(); it !=views.end(); ++it) {
        if(it->second) {
            it->second->colorUpdated();
        }
    }
}

// String Management (for nominal and ordinal properties)
void Controller::addStringMapping(string property, string value, int index) {
    string hash = property+"."+value;
    stringMappings[hash] = index;
    stringMappingIndex[property] = max(stringMappings[hash], index+1);
    print("Adding string mapping %s.%s  = %d\n", property.c_str(), value.c_str(), index);
}

void Controller::addStringMapping(string property, string value) {
    string hash = property+"."+value;
    if(stringMappings.find(hash)!=stringMappings.end()) {
        return;
    }
    if(stringMappingIndex.find(property)==stringMappingIndex.end()) {
        stringMappingIndex[property] = 0;
    }
    int index = stringMappingIndex[property];
    stringMappings[hash] = index;
    stringMappingIndex[property] = index+1;
    print("Adding string mapping %s.%s  = %d\n", property.c_str(), value.c_str(), index);
}

int Controller::stringToInt(string property, string value) {
    string hash = property+"."+value;
    if(stringMappings.find(hash)==stringMappings.end()) {
        addStringMapping(property, value);
    }
    //print("String %s.%s to int = %d\n", property.c_str(), value.c_str(), stringMappings[hash]);
    return stringMappings[hash];
}

string Controller::intToString(string property, int value) {
    vector<string> values = getStringValues(property);
    for(unsigned int i=0;i<values.size();i++) {
        if(stringToInt(property, values[i]) == value) {
            return values[i];
        }
    }
    return "none";
}

int Controller::numStringValues(string property) {
    return stringMappingIndex[property];
}
vector<string> Controller::getStringValues(string property) {
    vector<string> values;
    for(map<string,int>::const_iterator it = stringMappings.begin(); it!=stringMappings.end(); it++) {
        string s = (it->first);
        int idx = s.find(property+".");
        if(idx==0) {
            values.push_back(s.substr(idx+property.length()+1));
        }
    }
    return values;
}


// Search

void Controller::doSearch(string searchStr) {
    int (*pf)(int)=std::tolower;
    transform(searchStr.begin(), searchStr.end(), searchStr.begin(), pf);

    Graph *g = getGraph("graph");
	NodeIterator *it = g->createNodeIterator();
	for(it->begin();it->hasMoreElements();) {
		Node *n = (Node*) it->next();
        n->setPropertyInt("inSearch", 0);
        n->setPropertyInt("node.selected", 0);
        vector<string> properties = n->getProperties();
        for(unsigned k=0;k<properties.size();k++) {
					string v = g->getAsString(n, properties[k]);
            transform(v.begin(), v.end(), v.begin(), pf);
            size_t found;
            found = v.find(searchStr);
            if (found!=string::npos) {
                n->setPropertyInt("inSearch", 1);
                n->setPropertyInt("node.selected", 2);
            }
        }

    }
	g->destroyIterator(it);
    colorUpdated();
}


// Data
void Controller::addDataListener(DataListener *l) {
    assert(l);
    dataListeners.push_back(l);
}
void Controller::notifyDataAdded(const char *source, string event) {
    for(unsigned int i=0;i<dataListeners.size();i++) {
        dataListeners[i]->dataAdded(source, event);
    }

}


/******************/
/*	Short cuts    */
/******************/

void Controller::addShortcut(Shortcut *shortcut) {
	assert(shortcut);
	shortcut->setController(this);
	shortcuts[shortcut->getName()] = shortcut;
}

Shortcut *Controller::getShortcut(string name) {
	return shortcuts[name];
}

vector<string> Controller::getShortcutNames() {
    vector<string> names;
    for(map<string,Shortcut*>::const_iterator it = shortcuts.begin(); it!=shortcuts.end(); it++) {
        string s = (it->first);
		names.push_back(s);
    }
    return names;
}
